package top.v5it.japi.plus.core.exception.handler;

import cn.hutool.core.util.ReflectUtil;
import org.springframework.http.HttpHeaders;
import top.v5it.japi.plus.core.api.ErrorResult;
import top.v5it.japi.plus.core.api.ResultStatus;
import top.v5it.japi.plus.core.api.ResultStatusTemplate;
import top.v5it.japi.plus.core.exception.JapiException;

import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Set;

/**
 * 系统统一异常处理接口
 *
 * @author zhanpu
 */
public interface JapiResponseExceptionSet {

    /**
     * 响应headers字段值
     */
    String CACHE_CONTROL_VALUE = "no-store";

    /**
     * 响应headers字段值
     */
    String PRAGMA_VALUE = "no-cache";

    /**
     * 自定义全局异常
     *
     * @return
     */
    Set<Class<?>> getExceptionSet();

    /**
     * 异常是否存在或者可解析
     *
     * @param e 异常
     * @return true可解析，false不存在
     */
    default boolean exists(Exception e) {
        if (getExceptionSet().contains(e.getClass())) {
            return true;
        }

        if (e instanceof JapiException
                || e.getClass().isAssignableFrom(JapiException.class)) {
            return true;
        }

        Field[] fields = ReflectUtil.getFields(e.getClass());
        return Arrays
                .stream(fields)
                .anyMatch(v -> v.getDeclaringClass().isAssignableFrom(ResultStatusTemplate.class) || v.getType() == ResultStatusTemplate.class);
    }

    /**
     * 创建返回信息
     *
     * @param response             {@link HttpServletResponse}
     * @param resultStatusTemplate 响应结果
     * @return {@link ErrorResult}
     */
    default ErrorResult createReturnError(HttpServletResponse response, ResultStatusTemplate resultStatusTemplate) {

        response.setHeader(HttpHeaders.CACHE_CONTROL, CACHE_CONTROL_VALUE);
        response.setHeader(HttpHeaders.PRAGMA, PRAGMA_VALUE);
        response.setStatus(resultStatusTemplate.getStatus());

        return ErrorResult.failure(resultStatusTemplate);
    }

    /**
     * 创建返回信息
     *
     * @param response             {@link HttpServletResponse}
     * @param resultStatusTemplate 响应结果
     * @param message              描述
     * @return {@link ErrorResult}
     */
    default ErrorResult createReturnError(HttpServletResponse response, ResultStatusTemplate resultStatusTemplate, final String message) {

        response.setHeader(HttpHeaders.CACHE_CONTROL, CACHE_CONTROL_VALUE);
        response.setHeader(HttpHeaders.PRAGMA, PRAGMA_VALUE);
        response.setStatus(resultStatusTemplate.getStatus());

        return ErrorResult.failure(resultStatusTemplate, message);
    }

    /**
     * 创建返回信息
     *
     * @param response   {@link HttpServletResponse}
     * @param status     状态码
     * @param returnCode 响应编码
     * @param message    消息说明
     * @return {@link ErrorResult}
     */
    default ErrorResult createReturnError(HttpServletResponse response, final int status, final String returnCode, final String message) {

        response.setHeader(HttpHeaders.CACHE_CONTROL, CACHE_CONTROL_VALUE);
        response.setHeader(HttpHeaders.PRAGMA, PRAGMA_VALUE);
        response.setStatus(status);

        return message.contains("timeout")
                ? ErrorResult.failure(ResultStatus.THIRD_SERVICE_UNAVAILABLE)
                : ErrorResult.failure(status, returnCode, message);
    }

    /**
     * 创建返回信息
     *
     * @param response   {@link HttpServletResponse}
     * @param returnCode 响应编码
     * @param message    消息说明
     * @return {@link ErrorResult}
     */
    default ErrorResult createReturnError(HttpServletResponse response, final String returnCode, final String message) {

        ResultStatus resultStatus = ResultStatus.nullValueOf(returnCode);

        response.setHeader(HttpHeaders.CACHE_CONTROL, CACHE_CONTROL_VALUE);
        response.setHeader(HttpHeaders.PRAGMA, PRAGMA_VALUE);
        response.setStatus(resultStatus.getStatus());

        return ErrorResult.failure(resultStatus, message);
    }
}
